package com.linb.pan.server.modules.recycle.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.linb.pan.core.constants.BPanConstants;
import com.linb.pan.core.exception.BPanBusinessException;
import com.linb.pan.server.common.stream.channel.PanChannels;
import com.linb.pan.server.common.stream.event.file.FilePhysicalDeleteEvent;
import com.linb.pan.server.common.stream.event.file.FileRestoreEvent;
import com.linb.pan.server.modules.file.context.QueryFileListContext;
import com.linb.pan.server.modules.file.entity.BPanUserFile;
import com.linb.pan.server.modules.file.enums.DelFlagEnum;
import com.linb.pan.server.modules.file.service.IUserFileService;
import com.linb.pan.server.modules.file.vo.BPanUserFileVO;
import com.linb.pan.server.modules.recycle.context.DeleteContext;
import com.linb.pan.server.modules.recycle.context.QueryRecycleFileListContext;
import com.linb.pan.server.modules.recycle.context.RestoreContext;
import com.linb.pan.server.modules.recycle.service.IRecycleService;
import com.linb.pan.stream.core.IStreamProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class RecycleServiceImpl implements IRecycleService {

    @Autowired
    @Qualifier(value = "defaultStreamProducer")
    private IStreamProducer producer;

    @Autowired
    private IUserFileService userFileService;

    /**
     * 查询回收站文件列表
     */
    @Override
    public List<BPanUserFileVO> recycles(QueryRecycleFileListContext context) {
        QueryFileListContext queryContext = new QueryFileListContext();
        queryContext.setUserId(context.getUserId());
        queryContext.setDelFlag(DelFlagEnum.YES.getCode());
        return userFileService.getFileList(queryContext);
    }

    /**
     * 批量还原文件
     */
    @Override
    public void restore(RestoreContext context) {
        //1.操作权限校验
        checkRestorePermission(context);
        //2.重名校验
        checkRestoreFilename(context);
        //3.执行还原操作
        doRestore(context);
        //4.发布事件
        afterRestore(context);
    }

    /**
     * 彻底删除文件
     */
    @Override
    public void delete(DeleteContext context) {
        //1.校验操作权限
        checkFileDeletePermission(context);
        //2.递归查找所有子文件
        findAllFileRecords(context);
        //3.批量删除文件
        doDelete(context);
        //4.发布事件
        afterDelete(context);
    }

    /*==============================================private==============================================*/

    /**
     * 操作权限校验
     */
    private void checkRestorePermission(RestoreContext context) {
        //查询还原的文件
        List<Long> fileIdList = context.getFileIdList();
        List<BPanUserFile> records = userFileService.listByIds(fileIdList);
        if (CollectionUtils.isEmpty(records)) {
            throw new BPanBusinessException("要还原的文件不存在");
        }
        //提取userId 转换为Set
        Set<Long> userSet = records.stream().map(BPanUserFile::getUserId).collect(Collectors.toSet());
        //只能是一个用户的
        if (userSet.size() > 1) {
            throw new BPanBusinessException("不能还原别人的文件");
        }
        //用户要对应上
        if (!userSet.contains(context.getUserId())) {
            throw new BPanBusinessException("不能还原别人的文件");
        }
        context.setRecords(records);
    }

    /**
     * 重名校验
     */
    private void checkRestoreFilename(RestoreContext context) {
        //检查还原文件列表中，是否有重名的
        List<BPanUserFile> restoreFileList = context.getRecords();
        Set<String> filenameSet = restoreFileList.stream().map(r -> r.getFilename() + BPanConstants.COMMON_SEPARATOR + r.getFileId())
                .collect(Collectors.toSet());
        if (filenameSet.size() != restoreFileList.size()) {
            throw new BPanBusinessException("还原文件失败，还原文件列表中存在重名文件");
        }
        //检查还原文件列表中，当前文件夹下是否存在同名文件
        for (BPanUserFile record : restoreFileList) {
            QueryWrapper queryWrapper = Wrappers.query();
            queryWrapper.eq("user_id", context.getUserId());
            queryWrapper.eq("filename", record.getFilename());
            queryWrapper.eq("parent_id", record.getParentId());
            queryWrapper.eq("del_flag", DelFlagEnum.NO.getCode());
            if (userFileService.count(queryWrapper) > 0) {
                throw new BPanBusinessException("还原文件" + record.getFilename() + "失败，当前文件夹下存在同名文件");
            }
        }
    }

    /**
     * 文件还原操作
     */
    private void doRestore(RestoreContext context) {
        //获取校验完成后的数据
        List<BPanUserFile> records = context.getRecords();
        //批量设置
        records.stream().forEach(r -> {
            r.setDelFlag(DelFlagEnum.NO.getCode());
            r.setUpdateUser(context.getUserId());
            r.setUpdateTime(new Date());
        });
        boolean updateFlag = userFileService.updateBatchById(records);
        if (!updateFlag) {
            throw new BPanBusinessException("文件还原失败");
        }
    }

    /**
     * 文件还原后 发布事件
     */
    private void afterRestore(RestoreContext context) {
        FileRestoreEvent event = new FileRestoreEvent(context.getFileIdList());
        producer.sendMessage(PanChannels.FILE_RESTORE_OUTPUT, event);
    }

    /**
     * 删除文件-校验操作权限
     */
    private void checkFileDeletePermission(DeleteContext context) {
        QueryWrapper<BPanUserFile> queryWrapper = Wrappers.query();
        List<Long> fileIdList = context.getFileIdList();
        queryWrapper.eq("user_id", context.getUserId());
        queryWrapper.in("file_id", fileIdList);
        List<BPanUserFile> records = userFileService.list(queryWrapper);
        if (CollectionUtils.isEmpty(records)) {
            throw new BPanBusinessException("回收站中无该文件");
        }
        if (fileIdList.size() != records.size()) {
            throw new BPanBusinessException("无法删除他人文件");
        }
        context.setRecords(records);
    }

    /**
     * 递归查找所有子文件
     */
    private void findAllFileRecords(DeleteContext context) {
        List<BPanUserFile> records = context.getRecords();
        List<BPanUserFile> allRecords = userFileService.findAllFileRecords(records);
        context.setAllRecords(allRecords);
    }

    /**
     * 批量删除文件
     */
    private void doDelete(DeleteContext context) {
        List<Long> fileIdList = context.getFileIdList();
        if (!userFileService.removeByIds(fileIdList)) {
            throw new BPanBusinessException("批量删除文件失败");
        }
    }

    /**
     * 物理删除文件-发布事件
     */
    private void afterDelete(DeleteContext context) {
        FilePhysicalDeleteEvent event = new FilePhysicalDeleteEvent(context.getAllRecords());
        producer.sendMessage(PanChannels.PHYSICAL_DELETE_FILE_OUTPUT, event);
    }

}
